package game.model;

import java.awt.Color;
import java.util.HashSet;
import java.util.Set;

/**
 * Clase SemiEspejo, tiene el mismo comportamiento que el espejo doble,
 * pero permite mezclar colores de rayos.
 * Ademas de reflejar, permite ser atravesado por un rayo.
 *
 */

public class SemiEspejo extends Espejo {
	private EspejoDoble ed;
	
	/**
	 * Constructor de la clase Semi Espejo.
	 * 
	 * @param orientacion orientacion inicial del semi espejo.
	 */
	
	public SemiEspejo(int orientacion) {
		this.ed = new EspejoDoble(orientacion);
		setImagen(5);
		this.setOrientacion(orientacion);
	}
	
	@Override
	public void rotar(){
		this.setOrientacion((this.getOrientacion() + 1) % 2);
		this.ed.rotar();
	}

	@Override
	public Set<Rayo> getSalida(Rayo entrada) {
		return new HashSet<Rayo>();
	}
	
	@Override
	public int getOrientacion() {
		return super.getOrientacion();
	}

	@Override
	public String salvarEstado(String ubicacion) {
		return ubicacion + "5" + "," + getOrientacion() + "," + "0" + "," + "0" + "," + "0";
	}

	@Override
	public Set<Rayo> getSalida(Rayo entrada, Set<Rayo> anterior) {
		Set<Rayo> salidaActual = new HashSet<Rayo>();
		Set<Rayo> salidaAuxiliar = new HashSet<Rayo>();
		Color sumaColor = entrada.getColor();
		Rayo[] dirAuxi = new Rayo[4];
		Rayo[] dir = new Rayo[4];

		for(Rayo rayo : anterior){
			Color colorAux = mix(rayo.getColor(), entrada.getColor());
			if(!entrada.mismoColor(rayo) && rayo.isEntrando()){
				sumaColor = colorAux;
			}
		}
		
		for(Rayo rayo : anterior){
			int i;
			if(rayo.isEntrando()){
				i = rayo.getOrientacion();
			} else {
				i = (rayo.getOrientacion()+2)%4;
			}
			dir[i] = rayo;
			Rayo nuevo = new Rayo(rayo.getColor(), rayo.getOrientacion());
			nuevo.setEntrando(rayo.isEntrando());
			nuevo.setImagen(rayo.getImagen());
			dirAuxi[i] = nuevo;
		}
		
		Rayo auxEnt1 = new Rayo(entrada.getColor(), entrada.getOrientacion());
		auxEnt1.setImagen(10);
		auxEnt1.setEntrando(false);
		
		salidaAuxiliar = ed.getSalida(entrada, anterior);
		salidaAuxiliar.add(auxEnt1);
		
		for(Rayo rayo : salidaAuxiliar){
			int i;
			if(rayo.isEntrando()){
				i = rayo.getOrientacion();
			} else {
				i = (rayo.getOrientacion()+2)%4;
			}
			dir[i] = rayo;
		}
		
		Rayo auxEnt2 = new Rayo(entrada.getColor(), entrada.getOrientacion());
		auxEnt2.setImagen(9);
		auxEnt2.setEntrando(true);
		int k = auxEnt2.getOrientacion();
		dir[k] = auxEnt2;
		
		for(Rayo rayo : salidaAuxiliar){
			Rayo nuevo = new Rayo(rayo.getColor(), rayo.getOrientacion());
			nuevo.setEntrando(rayo.isEntrando());
			nuevo.setImagen(rayo.getImagen());
			salidaActual.add(nuevo);
		}
		
		anterior.clear();
		
		for(int i=0; i < dir.length; i++){
			if(dir[i] != null){
				anterior.add(dir[i]);
			}
		}
		
		if(CalcularSaliendo(dir) == 2){
			for(Rayo rayo : anterior){
				if(!rayo.isEntrando()){
					rayo.setColor(sumaColor);
				}
			}
			for(Rayo rayo : salidaActual){
				rayo.setColor(sumaColor);
			}
		}
		
		for(int i = 0; i < dir.length; i++){
			if(dir[i] == null && dirAuxi[i] != null || dir[i] != null && dirAuxi[i] == null){
				return salidaActual;
			} else if(dir[i]!=null && dirAuxi[i]!= null && !dir[i].mismoColor(dirAuxi[i])){
				return salidaActual;
			}
		}
		
		return new HashSet<Rayo>();
		
	}
	
	/**
	 * Mezcla colores, en funcion de dos colores de entrada, retorna uno nuevo
	 * de salida del espejo.
	 * 
	 * @param c1 primer color.
	 * @param c2 segundo color.
	 * @return Color color que sale de la mezcla de los parametros.
	 */
	
	public static Color mix(Color c1, Color c2) {
		return new Color(Math.min(c1.getRed() + c2.getRed(), 255), 
				Math.min(c1.getGreen() + c2.getGreen(), 255),
				Math.min(c1.getBlue() + c2.getBlue(), 255));
	}
	
	/**
	 * Calcula la cantidad de rayos que estan saliendo del semi espejo
	 * 
	 * @param rayos arreglo de rayos.
	 * @return CantSaliendo cantidad de rayos que estan saliendo del espejo.
	 */
	
	private int CalcularSaliendo(Rayo[] rayos){
		int cantSaliendo = 0;
		for(int i=0; i < rayos.length; i++){
			if(rayos[i] != null){
				if(!rayos[i].isEntrando()){
					cantSaliendo++;
				}
			}
		}
		return cantSaliendo;
	}
}